/* 
 * Copyright 2010-2011 Johannes Tuikkala <johannes.tuikkala@itmill.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.vaadin.webcamforvaadin.gwt.client.ui;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;

public class VWebCamForVaadin extends Composite implements Paintable {
	private static final String FLASH_ID = "fxwebcamforvaadinPID_SVAADIN_WEBCAM_PID";
	private static final String FLASH_WIDTH = "320px";
	private static final String FLASH_HEIGHT = "240px";
	private String uidlId;
	protected ApplicationConnection client;

	private boolean flashInited = false;
	private HTML flash;

	private int webcamWidth = 640;
	private int webcamHeight = 480;
	private String sessionId;
	private String postTargetUri;
	private String baseurl;

	/**
	 * Constructor
	 */
	public VWebCamForVaadin() {
		flash = new HTML();
		initWidget(flash);
	}

	/**
	 * This method accepts parses the uidl sent by the server
	 * 
	 * @param UIDL
	 *            uidl
	 * @param ApplicationConnection
	 *            client
	 */
	public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
		uidlId = uidl.getId();
		this.client = client;
		boolean captureNow = false;

		if (uidl.hasAttribute("capturenow")) {
			captureNow = uidl.getBooleanAttribute("capturenow");
		}
		if (sessionId == null) {
			sessionId = Cookies.getCookie("JSESSIONID");
		}
		this.postTargetUri = GWT.getHostPageBaseURL()
				+ uidl.getStringVariable("postTargetUri").substring(5);
		this.baseurl = GWT.getModuleBaseURL();
		this.webcamWidth = uidl.getIntAttribute("webcamWidth");
		this.webcamHeight = uidl.getIntAttribute("webcamHeight");
		VConsole.log("StreamVariable: " + postTargetUri);

		if (!flashInited) {
			setFlash();
			initializeMethods(uidlId);
		}
		if (flashInited && webcamWidth > 0 && webcamHeight > 0) {
			VConsole.log(webcamWidth + "x" + webcamHeight);
			setFlash();
			initializeMethods(uidlId);
		}
		if (flashInited && captureNow) {
			captureNow(FLASH_ID);
		}
	}

	/**
	 * Send parameter (name,value) pair into flash
	 * 
	 * @param name
	 * @param value
	 */
	private native void setParameter(String flashId, String name, String value) /*-{   
																				try {
																				$doc[flashId].setParameter(name.toString(), value.toString());
																				}
																				catch(e) {
																				$wnd.alert(e.message+': '+flashId+' name: '+$doc[flashId].name);
																				}   
																				}-*/;

	/**
	 * Inform flash to capture image
	 * 
	 * @param flashId
	 * @param width
	 * @param height
	 */
	public native void captureNow(String flashId) /*-{   
													try {
													$doc[flashId].captureNow();
													}
													catch(e) {
													$wnd.alert(e.message+': '+flashId+' name: '+$doc[flashId].name);
													}   
													}-*/;

	/**
	 * Flash calls this method via javascript to set new captured image
	 * 
	 * @param bytes
	 */
	public void setCapturedImage(String bytes) {
		VConsole.log("flashInited");
		flashInited = true;
		setParameter(FLASH_ID, "jsessioid", sessionId);
		setParameter(FLASH_ID, "postaction", postTargetUri);
		setParameter(FLASH_ID, "baseurl", baseurl);
		setParameter(FLASH_ID, "webcamWidth", String.valueOf(webcamWidth));
		setParameter(FLASH_ID, "webcamHeight", String.valueOf(webcamHeight));
		if (uidlId == null || client == null) {
			return;
		}
		if (bytes != null && bytes.length() > 0) {
			client.updateVariable(uidlId, "capturedimage", bytes, true);
		}
	}

	/**
	 * Flash calls this method via javascript if error is occurred
	 * 
	 * @param message
	 */
	public void setErrorMessage(String msg) {
		flashInited = true;
		if (uidlId == null || client == null) {
			return;
		}
		client.updateVariable(uidlId, "errormessage", msg, true);
	}

	/**
	 * Initialize the native javascript functions needed for the flash <-> GWT
	 * communication
	 * 
	 * @param String
	 *            id
	 */
	public native void initializeMethods(String id) /*-{
													   var app = this;
													   
													   if($wnd.vaadin.webcamforvaadin == null)
													   var webcamforvaadin = [];
													   else
													   var webcamforvaadin = $wnd.vaadin.webcamforvaadin;
													   
													   webcamforvaadin['setCapturedImage_' + id] = function(image) {
													   	app.@org.vaadin.webcamforvaadin.gwt.client.ui.VWebCamForVaadin::setCapturedImage(Ljava/lang/String;)(image);
													   };
													   
													   webcamforvaadin['setErrorMessage_' + id] = function(msg) {
													   	app.@org.vaadin.webcamforvaadin.gwt.client.ui.VWebCamForVaadin::setErrorMessage(Ljava/lang/String;)(msg);
													   };
													   
													   $wnd.vaadin.webcamforvaadin = webcamforvaadin;
													   }-*/;

	/**
	 * Set the HTML coding of the flash movie. This isn't done until the
	 * updateFromUIDL method is called for the first time. The reason is that we
	 * use an id from the UIDL to uniquely identify all instances of this
	 * widget.
	 */
	private void setFlash() {
		String html = "<object id=\"fxwebcamforvaadin"
				+ uidlId
				+ "\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\""
				+ FLASH_WIDTH
				+ "\""
				+ " height=\""
				+ FLASH_HEIGHT
				+ "\" codebase=\"http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0\">"
				+ "<param name=\"movie\" value=\""
				+ GWT.getModuleBaseURL()
				+ "webcamforvaadinflash.swf\">"
				+ "<param name=\"quality\" value=\"high\">"
				+ "<param name=\"allowScriptAccess\" value=\"sameDomain\" /> "
				+ "<param name=\"flashVars\" value=\"pid="
				+ uidlId
				+ "\" />"
				+ "<embed name=\"fxwebcamforvaadin"
				+ uidlId
				+ "\" src=\""
				+ GWT.getModuleBaseURL()
				+ "webcamforvaadinflash.swf\" width=\""
				+ FLASH_WIDTH
				+ "\" height=\""
				+ FLASH_HEIGHT
				+ "\" "
				+ "quality=\"high\" "
				+ "param name=\"allowScriptAccess\" value=\"sameDomain\" "
				+ "pluginspage=\"http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\">"
				+ "</embed>" + "</object>";
		flash.setHTML(html);
	}
}